import datetime
import base64

from django.contrib.auth.models import User
from apps.files.managers import FileManager
from apps.course.functions import course_reverse
from django.contrib.contenttypes import generic
from django.contrib.contenttypes.models import ContentType
from django.contrib.sites.models import Site
from django.db import models
from django.core import urlresolvers
from django.utils.translation import ugettext_lazy as _
from django.conf import settings
import django.db.models.options as options
from django.template.defaultfilters import slugify
from tags.templatetags.sanitize import sanitize
from storage import OverwriteStorage
import re
import os
import imghdr

options.DEFAULT_NAMES = options.DEFAULT_NAMES + ('form_save_data',)

FILE_MAX_LENGTH = getattr(settings,'FILE_MAX_LENGTH',3000)

EXTENSION_ICONS = {
    'ac3':'ac3.png',
    'ai':'ai.png',
    'aiff':'aiff.png',
    'ani':'ani.png',
    'asf':'asf.png',
    'au':'au.png',
    'avi':'avi.png',
    'bat':'bat.png',
    'bin':'bin.png',
    'bmp':'bmp.png',
    'bup':'bup.png',
    'cab':'cab.png',
    'cal':'cal.png',
    'cat':'cat.png',
    'cur':'cur.png',
    'dat':'dat.png',
    'dcr':'dcr.png',
    'default':'default.png',
    'der':'der.png',
    'dic':'dic.png',
    'dll':'dll.png',
    'doc':'doc.png',
    'docx':'docx.png',
    'dvd':'dvd.png',
    'dwg':'dwg.png',
    'dwt':'dwt.png',
    'fon':'fon.png',
    'gif':'gif.png',
    'hlp':'hlp.png',
    'hst':'hst.png',
    'html':'html.png',
    'ico':'ico.png',
    'ifo':'ifo.png',
    'inf':'inf.png',
    'ini':'ini.png',
    'java':'java.png',
    'jif':'jif.png',
    'jpg':'jpg.png',
    'log':'log.png',
    'm4a':'m4a.png',
    'mmf':'mmf.png',
    'mmm':'mmm.png',
    'mov':'mov.png',
    'mp2':'mp2.png',
    'mp2v':'mp2v.png',
    'mp3':'mp3.png',
    'mp4':'mp4.png',
    'mpeg':'mpeg.png',
    'mpg':'mpeg.png',
    'msp':'msp.png',
    'pdf':'pdf.png',
    'png':'png.png',
    'ppt':'ppt.png',
    'pptx':'pptx.png',
    'psd':'psd.png',
    'ra':'ra.png',
    'rar':'rar.png',
    'reg':'reg.png',
    'rtf':'rtf.png',
    'theme':'theme.png',
    'tiff':'tiff.png',
    'tlb':'tlb.png',
    'ttf':'ttf.png',
    'txt':'txt.png',
    'vob':'vob.png',
    'wav':'wav.png',
    'wma':'wma.png',
    'wmv':'wmv.png',
    'wpl':'wpl.png',
    'wri':'wri.png',
    'xls':'xls.png',
    'xlsx':'xlsx.png',
    'xml':'xml.png',
    'xsl':'xsl.png',
    'zip':'zip.png',
    'tgz':'zip.png',
    'gz':'zip.png',
}


def template_format(str):
    """
    This is django's slugify but replaces spaces and
    dashes with underscores. Also ensures a name doesn't
    start or end with an underscore.
    """
    str = re.sub('[-\s]+', '_', slugify(str))
    return str.strip('_')
    
def get_file_upload_path(instance, filename):
    filename_pieces = filename.rsplit('.')
    name = filename_pieces[0]
    ext = ''
    if len(filename_pieces) > 1: ext = '.'.join(filename_pieces[1:])
    ret_string = "%s/%s/%s" % (template_format(instance.content_type), template_format(instance.object_pk), template_format(name))
    if ext: ret_string += ".%s" % ext
    return ret_string

class BaseFileAbstractModel(models.Model):
    """
    An abstract base class that any custom file models probably should
    subclass.
    """

    # Content-object field
    content_type   = models.ForeignKey(ContentType,
            verbose_name=_('content type'),
            related_name="content_type_set_for_%(class)s")
    object_pk      = models.TextField(_('object ID'))
    content_object = generic.GenericForeignKey(ct_field="content_type", fk_field="object_pk")

    class Meta:
        abstract = True

    def get_content_object_url(self):
        """
        Get a URL suitable for redirecting to the content object.
        """
        return urlresolvers.course_reverse(
            "files-url-redirect",
            args=(self.content_type_id, self.object_pk)
        )

class File(BaseFileAbstractModel):
    """
    A file associated with some object.
    """

    _data = models.TextField(db_column='data',blank=True)
    def set_data(self, data):
        self._data = base64.encodestring(data)
    def get_data(self):
        return base64.decodestring(self._data)
    data = property(get_data, set_data)
    
    in_db = models.BooleanField(default=False)
    file = models.FileField(upload_to=get_file_upload_path,storage=OverwriteStorage())
    file_title = models.CharField("Title",blank=True,max_length=255)
    file_description = models.CharField("Description",null=True,blank=True,max_length=512)
    filename = models.CharField(blank=True, max_length=255)
    
    # Who posted this file? If ``user`` is set then it was an authenticated
    # user; otherwise at least user_name should have been set and the file
    # was posted by a non-authenticated user.
    user        = models.ForeignKey(User, verbose_name=_('user'),
                    blank=True, null=True, related_name="%(class)s_files")

    # Metadata about the file
    submit_date = models.DateTimeField(_('date/time submitted'), default=None)
    ip_address  = models.IPAddressField(_('IP address'), blank=True, null=True)
    is_public   = models.BooleanField(_('is public'), default=True,
                    help_text=_('Uncheck this box to make the file effectively ' \
                                'disappear from the site.'))
    is_removed  = models.BooleanField(_('is removed'), default=False,
                    help_text=_('Check this box if the file is inappropriate. ' \
                                'A "This file has been removed" message will ' \
                                'be displayed instead.'))

    # Manager
    objects = FileManager()

    class Meta:
        db_table = "django_files"
        ordering = ('-submit_date',)
        permissions = [("can_moderate", "Can moderate files")]
        verbose_name = _('file')
        verbose_name_plural = _('files')
        form_save_data = ['file','file_title','file_description']
        
    def __unicode__(self):
        return self.url()

    def save(self, *args, **kwargs):
        if self.file:
            if self.submit_date is None:
                self.submit_date = datetime.datetime.now()
            filename_pieces = os.path.basename(self.file.name).rsplit('.')
            name = template_format(filename_pieces[0])
            ext = ''
            for item in filename_pieces[1:]:
                ext += ".%s" % template_format(item)
            self.filename = "%s%s" % (template_format(name),ext)
            if self.file_title is None:
                self.file_title = name
            self.file_title = sanitize(self.file_title)
            self.file_description = sanitize(self.file_description)
        super(File, self).save(*args, **kwargs)
    
    def _get_userinfo(self):
        """
        Get a dictionary that pulls together information about the poster
        safely for both authenticated and non-authenticated files.

        This dict will have ``name``, ``email``, and ``url`` fields.
        """
        if not hasattr(self, "_userinfo"):
            self._userinfo = {
                "name"  : self.user_name,
            }
            if self.user_id:
                u = self.user

                # If the user has a full name, use that for the user name.
                # However, a given user_name overrides the raw user.username,
                # so only use that if this file has no associated name.
                if u.get_full_name():
                    self._userinfo["name"] = self.user.get_full_name()
                elif not self.user_name:
                    self._userinfo["name"] = u.username
        return self._userinfo
    userinfo = property(_get_userinfo, doc=_get_userinfo.__doc__)

    def _get_name(self):
        return self.userinfo["name"]
    def _set_name(self, val):
        if self.user_id:
            raise AttributeError(_("This file was posted by an authenticated "\
                                   "user and thus the name is read-only."))
        self.user_name = val
    name = property(_get_name, _set_name, doc="The name of the user who posted this file")

    def get_absolute_url(self, anchor_pattern="#c%(id)s"):
        return self.get_content_object_url() + (anchor_pattern % self.__dict__)
    def template_title(self):
        return template_format(self.title())
    def title(self):
        if self.file_title: return self.file_title
        return sanitize(template_format(os.path.basename(self.filename).rsplit('.',1)[0]))
    def description(self):
        return self.file_description
    def url(self):
        return course_reverse('files-serve-file',kwargs={'content_type':self.content_type.name, 'object_pk':self.object_pk, 'filename':self.filename})
    def image_type(self):
        return imghdr.what(self.file)
    def extension(self):
        name,ext = self.file.name.rsplit('.',1)
        return ext
    def icon(self):
        name,ext = self.file.name.rsplit('.',1)
        if ext in EXTENSION_ICONS: return EXTENSION_ICONS[ext]
        else: return EXTENSION_ICONS['default']
        
